﻿// $ PURE $ // class name and mean

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace CodeTable
{
    partial class GridData
    {
        public class Visual
        {
            GridData owner = null;
            private int[] columnWidths = null;
            private int[] rowHeights = null;
            private int totalWidth;
            private int totalHeight;

            private const int MinCellDimension = 32;
            private const float columnDelimiterWidth = 4.0f;
            private const float rowDelimiterWidth = 1.0f;

            public ScintillaNET.MarginCollection margins;

            public Visual(GridData owner, ScintillaNET.MarginCollection margins)
            {
                this.owner = owner;
                this.margins = margins;
            }

            public void Initialize()
            {
                this.columnWidths = new int[this.owner.MaxColumns];
                this.rowHeights = new int[this.owner.MaxRows];
            }

            public int[] ColumnWidths
            {
                get
                {
                    return columnWidths;
                }
            }

            public int[] RowHeights
            {
                get
                {
                    return rowHeights;
                }
            }

            public float ColumnDelimiterWidth
            {
                get
                {
                    return columnDelimiterWidth;
                }
            }

            public float RowDelimiterWidth
            {
                get
                {
                    return rowDelimiterWidth;
                }
            }

            public Size TotalSize
            {
                get
                {
                    return new Size(totalWidth, totalHeight);
                }
            }

            public bool RefreshColumnWidth(Point gridCoordinate) // TODO: call it by event WidthsChanged
            {
                int originalWidth = columnWidths[gridCoordinate.X];
                int originalLength = columnWidths.Length;
                RefreshColumnWidths();
                return (originalWidth != columnWidths[gridCoordinate.X]) || (originalLength != columnWidths.Length);
            }

            public bool RefreshRowHeight(Point gridCoordinate) // TODO: call it by event HeightsChanged
            {
                int originalHeight = rowHeights[gridCoordinate.Y];
                int originalLength = rowHeights.Length;
                RefreshRowHeights();
                return (originalHeight != rowHeights[gridCoordinate.Y]) || (originalLength != rowHeights.Length);
            }

            public void RefreshColumnWidths() // TODO: call it by event WidthsChanged
            {
                int ownerColumnCount = this.owner.MaxColumns;
                if (columnWidths.Length != ownerColumnCount)
                {
                    Array.Resize<int>(ref columnWidths, ownerColumnCount);
                }

                totalWidth = (int)(0.5f * columnDelimiterWidth + 0.5f);
                for (int column = 0; column < this.owner.MaxColumns; ++column)
                {
                    columnWidths[column] = 0;
                    for (int row = 0; row < this.owner.MaxRows; ++row)
                    {
                        Block block = this.owner.grid[column, row];
                        if (block == null)
                            continue;
                        columnWidths[column] = Math.Max(columnWidths[column], block.TextSize.Width);
                    }
                    columnWidths[column] = Math.Max(columnWidths[column], MinCellDimension);
                    totalWidth += columnWidths[column] + (int)columnDelimiterWidth;
                }
            }

            public void RefreshRowHeights() // TODO: call it by event HeightsChanged
            {
                int ownerRowCount = this.owner.MaxRows;
                if (rowHeights.Length != ownerRowCount)
                {
                    Array.Resize<int>(ref rowHeights, ownerRowCount);
                }

                totalHeight = (int)(0.5f * rowDelimiterWidth + 0.5f);
                for (int row = 0; row < this.owner.MaxRows; ++row)
                {
                    rowHeights[row] = 0;
                    for (int column = 0; column < this.owner.MaxColumns; ++column)
                    {
                        Block block = this.owner.grid[column, row];
                        if (block == null)
                            continue;
                        rowHeights[row] = Math.Max(rowHeights[row], block.TextSize.Height);
                    }
                    rowHeights[row] = Math.Max(rowHeights[row], MinCellDimension);
                    totalHeight += rowHeights[row] + (int)rowDelimiterWidth;
                }
            }

            public Point GetLocationByGridCoordinate(Point gridCoordinate)
            {
                int x = (int)(0.5f * columnDelimiterWidth + 0.5f);
                for (int column = 0; column < gridCoordinate.X; ++column)
                {
                    x += columnWidths[column] + (int)columnDelimiterWidth;
                }
                int y = (int)(0.5f * rowDelimiterWidth + 0.5f);
                for (int row = 0; row < gridCoordinate.Y; ++row)
                {
                    y += rowHeights[row] + (int)rowDelimiterWidth;
                }
                return new Point(x, y);
            }

            public Point GetGridCoordinateByLocation(Point location)
            {
                Point gridCoordinate = new Point(-1, -1);

                int x = location.X;
                x -= (int)(0.5f * columnDelimiterWidth + 0.5f);
                if (x > 0)
                {
                    for (int column = 0; column < this.owner.MaxColumns; ++column)
                    {
                        x -= columnWidths[column] + (int)columnDelimiterWidth;
                        if (x > 0)
                            continue;
                        gridCoordinate.X = column;
                        break;
                    }
                }
                else
                {
                    gridCoordinate.X = 0;
                }

                int y = location.Y;
                y -= (int)(0.5f * rowDelimiterWidth + 0.5f);
                if (y > 0)
                {
                    for (int row = 0; row < this.owner.MaxRows; ++row)
                    {
                        y -= rowHeights[row] + (int)rowDelimiterWidth;
                        if (y > 0)
                            continue;
                        gridCoordinate.Y = row;
                        break;
                    }
                }
                else
                {
                    gridCoordinate.Y = 0;
                }

                return gridCoordinate;
            }
        }
    }
}
